package com.maimao.order.serivce;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baidu.fsg.uid.impl.CachedUidGenerator;
import com.google.common.collect.Lists;
import com.maimao.core.constant.ListData;
import com.maimao.core.enums.IntegralActionType;
import com.maimao.core.exception.MaiMaoDaoException;
import com.maimao.core.model.resp.PageResult;
import com.maimao.core.model.resp.Result;
import com.maimao.core.utils.DateUtils;
import com.maimao.core.utils.MapUtils;
import com.maimao.core.utils.StringUtil;
import com.maimao.mg.service.MgCouponService;
import com.maimao.model.info.IntegralAction;
import com.maimao.model.info.input.UseCouponInput;
import com.maimao.model.order.Order;
import com.maimao.model.order.OrderGoods;
import com.maimao.model.order.OrderProcessing;
import com.maimao.model.order.OrderShop;
import com.maimao.model.order.enums.OrderShopStatus;
import com.maimao.model.order.enums.OrderStatus;
import com.maimao.model.order.enums.OrderType;
import com.maimao.model.order.enums.ShipStatus;
import com.maimao.model.order.es.EsOrder;
import com.maimao.model.order.es.EsOrderGoods;
import com.maimao.model.order.es.EsOrderShop;
import com.maimao.model.order.input.CommentStatusUpdateInput;
import com.maimao.model.order.input.CommitOrder;
import com.maimao.model.order.input.OrderSearchInput;
import com.maimao.model.order.vo.ExportOrderEntity;
import com.maimao.model.order.vo.OrderEx;
import com.maimao.model.order.vo.OrderShopEx;
import com.maimao.model.user.Shop;
import com.maimao.model.user.input.UpdateIntegralInput;
import com.maimao.order.aop.GlobalATTractionAspect;
import com.maimao.order.client.*;
import com.maimao.order.mapper.OrderGoodsMapper;
import com.maimao.order.mapper.OrderMapper;
import com.maimao.order.mapper.OrderProcessingMapper;
import com.maimao.order.mapper.OrderShopMapper;
import com.maimao.order.rabbit.RabbitSender;
import io.seata.core.context.RootContext;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import static com.maimao.model.es.EsBoolConvert.ONE;

/**
 * @author MaoLin Wang
 * @date 2021/1/18 5:03 下午
 */
@Slf4j
@Service
public class OrderService {

    @Autowired
    private CachedUidGenerator cachedUidGenerator;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderGoodsMapper orderGoodsMapper;

    @Autowired
    private OrderShopMapper orderShopMapper;

    @Autowired
    private OrderProcessingMapper orderProcessingMapper;

    @Autowired
    private RabbitSender rabbitSender;

    @Autowired
    private UserClient userClient;

    @Autowired
    private GoodsClient goodsClient;

    @Autowired
    private MgCouponService mgCouponService;

    @Autowired
    private CouponClient couponClient;

    @Autowired
    private IntegralActionClient integralActionClient;

    @Autowired
    private ShopClient shopClient;

    @Resource
    GlobalATTractionAspect globalATTractionAspect;

    @Autowired
    private EsClient esClient;


    /**
     * 提交普通订单
     *
     * @param commitOrder 订单
     * @param userId      用户id
     * @desc 【普通订单提交】需要用分布式事务 1、关于feign降级seata无法捕获异常问题 https://github.com/seata/seata/issues/2088
     * 2、https://github.com/seata/seata/issues/3398 ：该方案在降级中抛异常，虽然可行，但是降级抛异常会出发Hystrix异常，还要单独捕获该异常封装响应到前端，
     * 且不能确定是否是因为全局事务导致的，因此不如直接在降级中回滚事务，这里会因为xid unbind触发如下异常：，接着在Controller Advice中捕获该异常直接响应 Could not commit JDBC
     * transaction; nested exception is java.sql.SQLException: io.seata.core.exception.RmTransactionException: Response[
     * TransactionException[Could not found global transaction xid = 192.168.0.168:8091:2032611006]
     * 3、官方demo解释：https://gitee.com/itCjb/spring-cloud-alibaba-seata-demo
     */
    @GlobalTransactional(rollbackFor = Exception.class)
    @Transactional(rollbackFor = MaiMaoDaoException.class)
    public Result submit(CommitOrder commitOrder, Long userId) {
        Result result = checkOrder(commitOrder);
        if (result != null) {
            return result;
        }
        Long orderId = cachedUidGenerator.getUID();
        Order order = commitOrder.getOrder();
        order.setId(orderId);
        order.setUserId(userId);
        order.setCreateTime(DateUtils.now());
        order.setDeleted(false);
        order.setStatus(OrderStatus.NOT_PAY.getStatus());
        order.setType(OrderType.NORMAL.getStatus());
        orderMapper.insert(order);
        List<OrderShop> orderShopList = commitOrder.getOrderShopList();
        Integer freezeIntegral = 0;

        String xid = RootContext.getXID();
        System.out.println(xid);
        //key：skuId value：购买数量
        Map<Long, Integer> stockMap = new HashMap<>();

        List<Long> couponIds = new ArrayList<>(orderShopList.size());
        for (OrderShop orderShop : orderShopList) {
            orderShop.setOrderId(orderId);
            //运费暂时都设为0
            orderShop.setDeliveryFee(BigDecimal.ZERO);
            orderShop.setStatus(OrderShopStatus.NOT_PAY.getStatus());
            //暂未引入物流
            orderShop.setShipSn(String.valueOf(cachedUidGenerator.getUID()));
            orderShop.setShipName("顺丰");
            orderShop.setChangeStatus(0);
            orderShop.setDeleted(false);
            if (orderShop.getShopCouponId() != null && orderShop.getShopCouponId() > 0) {
                couponIds.add(orderShop.getShopCouponId());
            }

            orderShopMapper.insert(orderShop);


            List<OrderGoods> orderGoodsList = orderShop.getOrderGoodsList();
            for (OrderGoods orderGoods : orderGoodsList) {
                orderGoods.setOrderId(orderId)
                        .setComment(false)
                        .setReceive(false)
                        .setOrderShopId(orderShop.getId())
                        .setShippedStatus(ShipStatus.NOT_SHIP.getStatus());
                freezeIntegral += orderGoods.getIntegral() == null ? 0 : orderGoods.getIntegral();
                stockMap.put(orderGoods.getSkuId(), orderGoods.getNum());
                orderGoodsMapper.insert(orderGoods);
            }
        }


        //修改用户积分 用户积分 = 使用了积分？积分-积分减免*100：不变 冻结积分+=赠送的积分
        boolean useIntegral = false;
        Integer integral = 0;
        if (order.getUseIntegral() && order.getIntegral().compareTo(BigDecimal.ZERO) > 0) {
            useIntegral = true;
            integral = order.getIntegral().multiply(BigDecimal.valueOf(100)).intValue();
        }
        if (useIntegral || freezeIntegral > 0) {
            userClient.updateIntegral(UpdateIntegralInput.builder()
                    .integral(integral)
                    .freezeIntegral(freezeIntegral)
                    .cancel(false)
                    .useIntegral(useIntegral)
                    .userId(userId).build());
            saveIntegralAction(orderId, userId, freezeIntegral, integral, useIntegral, false);
        }
        //修改库存
        goodsClient.updateStock(1, stockMap);


        //优惠券状态修改
        updateCouponUsed(userId, order, couponIds, true);

        //回滚后不发送
        rabbitSender.sendOrderCommitMessage(orderId);
//        GlobalStatus localStatus = GlobalTransactionContext.getCurrent().getLocalStatus();
//        System.out.println(localStatus);
        return Result.okData(orderId.toString());
    }

    /**
     * 检查订单商品有效性
     */
    private Result checkOrder(CommitOrder commitOrder) {
        List<OrderShop> orderShopList = commitOrder.getOrderShopList();
        Set<Long> goodsId = new HashSet<>();
        Map<Long, Integer> skuNumMap = new HashMap<>();
        for (OrderShop orderShop : orderShopList) {
            List<OrderGoods> orderGoodsList = orderShop.getOrderGoodsList();
            for (OrderGoods orderGoods : orderGoodsList) {
                goodsId.add(orderGoods.getGoodsId());
                Long skuId = orderGoods.getSkuId();
                skuNumMap.merge(skuId, orderGoods.getNum(), Integer::sum);
            }
        }
        Result<Boolean> checkSpuBatchRes = goodsClient.checkSpuBatch(Lists.newArrayList(goodsId));
        if (checkSpuBatchRes == null || checkSpuBatchRes.getData() == null || !checkSpuBatchRes.getData()) {
            return Result.notValid("您的订单中存在下架商品，请重新选择商品");
        }
        Result<Boolean> checkSkuBatchRes = goodsClient.checkSkuBatch(skuNumMap);
        if (checkSkuBatchRes == null || checkSkuBatchRes.getData() == null || !checkSkuBatchRes.getData()) {
            return Result.notValid("您的订单中部分商品库存不足或已失效，请重新选择商品");
        }
        return null;
    }


    /**
     * 取消订单
     *
     * @param orderId
     */
    @GlobalTransactional(rollbackFor = Exception.class)
    @Transactional(rollbackFor = MaiMaoDaoException.class)
    public void cancelOrder(Long orderId, Long userId) {
        log.info("取消订单{}", orderId);
        //修改订单状态
        orderMapper.cancel(orderId, OrderStatus.CANCEL.getStatus(), DateUtils.now());
        orderShopMapper.updateStatus(orderId, OrderShopStatus.CANCEL.getStatus());
        Order order = orderMapper.selectById(orderId);
        List<OrderGoods> orderGoodsList = orderGoodsMapper.selectSkuIdAndIntegralByOrderId(orderId);
        Map<Long, Integer> stockMap = new HashMap<>();

        boolean updateCouponUsed = false;
        if (order.getSysCouponId() != null && order.getSysCouponId() > 0) {
            //恢复用户优惠券状态为未使用
            updateCouponUsed(userId, order, Lists.newArrayList(order.getSysCouponId()), false);
            updateCouponUsed = true;
        }
        if (!updateCouponUsed) {
            List<Long> couponIds = orderShopMapper.selectCouponIdsByOrderId(orderId);
            updateCouponUsed(userId, order, couponIds, false);
        }
        Integer freezeIntegral = 0;
        if (orderGoodsList != null && orderGoodsList.size() > 0) {
            List<Integer> integrals = orderGoodsList.stream().map(OrderGoods::getIntegral).collect(Collectors.toList());

            for (Integer integral : integrals) {
                freezeIntegral += integral;
            }
            for (OrderGoods orderGoods : orderGoodsList) {
                stockMap.put(orderGoods.getSkuId(), orderGoods.getNum());
            }
        }
        Integer totalIntegral = 0;

        if (order.getUseIntegral()) {
            //使用了积分
            totalIntegral = order.getIntegral().multiply(BigDecimal.valueOf(100)).intValue();
        }

        //积分修改为原样
        userClient.updateIntegral(UpdateIntegralInput.builder()
                .userId(userId)
                .cancel(true)
                .useIntegral(order.getUseIntegral())
                .freezeIntegral(freezeIntegral)
                .integral(totalIntegral).build());
        saveIntegralAction(orderId, userId, freezeIntegral, totalIntegral, order.getUseIntegral(), true);

        //增加库存
        goodsClient.updateStock(0, stockMap);


    }


    /**
     * 支付(分布式事务有小问题尚未解决)
     */
//    @GlobalTransactional(rollbackFor = Exception.class)
    @Transactional(rollbackFor = MaiMaoDaoException.class)
    public boolean pay(Long orderId, Long userId) {
        OrderProcessing orderProcessing = orderProcessingMapper.selectById(orderId);
        if (orderProcessing != null) {
            //当前订单实际已取消
            return false;
        }
        //修改订单状态
        if (orderMapper.updateStatusAndPayTime(orderId, OrderStatus.PAID.getStatus(), DateUtils.now()) == 1) {


            orderShopMapper.updateStatus(orderId, OrderShopStatus.PAID.getStatus());

            //冻结积分 -= 订单赠送的总积分 用户积分 += 订单赠送的总积分

            List<OrderGoods> orderGoodsList = orderGoodsMapper.selectSkuIdAndIntegralByOrderId(orderId);

            Integer totalIntegral = 0;
            if (orderGoodsList != null && orderGoodsList.size() > 0) {
                List<Integer> integrals = orderGoodsList.stream().map(OrderGoods::getIntegral).collect(Collectors.toList());

                //key：商品id value:购买数量
                Map<Long, Integer> sellCountMap = new HashMap<>();
                for (OrderGoods orderGoods : orderGoodsList) {
                    Long goodsId = orderGoods.getGoodsId();
                    sellCountMap.merge(goodsId, orderGoods.getNum(), Integer::sum);
                }
                if (sellCountMap.size() > 0) {
                    goodsClient.addSellCount(sellCountMap);
                }

                for (Integer integral : integrals) {
                    totalIntegral += integral;
                }
            }

            userClient.updateIntegral(UpdateIntegralInput.builder()
                    .integral(totalIntegral)
                    .cancel(true)
                    .useIntegral(true)
                    .freezeIntegral(totalIntegral)
                    .userId(userId).build());
            if (totalIntegral > 0) {
                integralActionClient.saveBatch(Lists.newArrayList(IntegralAction.builder()
                                .createTime(DateUtils.now())
                                .freeze(IntegralActionType.GOODS_IN.getFreeze())
                                .incr(IntegralActionType.GOODS_IN.getIncr())
                                .num(totalIntegral)
                                .relatedId(orderId)
                                .userId(userId)
                                .type(IntegralActionType.GOODS_IN.getType())
                                .build(),
                        IntegralAction.builder()
                                .createTime(DateUtils.now())
                                .freeze(IntegralActionType.GOODS_OUT.getFreeze())
                                .incr(IntegralActionType.GOODS_OUT.getIncr())
                                .num(totalIntegral)
                                .relatedId(orderId)
                                .userId(userId)
                                .type(IntegralActionType.GOODS_OUT.getType())
                                .build()));
            }

            return true;
        }
        return false;


    }

    /**
     * 分页条件查询用户订单列表 TODO 问题：为了进行多条件查询且对orderShop表分页 使用了子查询 造成 ==> 索引失效，且子查询内根据时间排序因为被mysql优化而失效， TODO
     * 网上说添加LIMIT就不会优化排序，但还是有问题，如LIMIT 0,2 和2,2 虽然 第0页和第1页的日期是排序的  但是一个页内的数据未排序 TODO 索引解决：可以不使用子查询 但无法按照orderShop个数分页
     * TODO 日期解决：暂时在外部查询再进行一次排序 但效率极地 后期待修改优化
     */
    public PageResult<OrderShopEx> queryUserOrderList(OrderSearchInput input, Integer page, Integer size, Long userId) {
        List<OrderEx> orderExes = orderMapper.selectCompleteData(userId, input.getCommentType(), input.getFromTime(), input.getToTime(), input.getStatus(), input.getShippedStatus(), input.getReceive(), input.getOrderId(), input.getTitle(), input.getGoodsId(), input.getShopId(), input.getDeleted(), (page - 1) * size, size);
        Set<Long> orderShopIdSet = orderMapper.selectCompleteDataCount(userId, input.getCommentType(), input.getFromTime(), input.getToTime(), input.getStatus(), input.getShippedStatus(), input.getReceive(), input.getOrderId(), input.getTitle(), input.getDeleted(), input.getGoodsId(), input.getShopId());
        List<OrderShopEx> res = new ArrayList<>();
        OrderShopEx vo = null;
        if (orderExes != null && orderExes.size() > 0) {
            boolean filterBuyer = false;
            if (!StringUtils.isEmpty(input.getBuyerName())) {
                filterBuyer = true;
            }
            //key：订单id value：买家名称
            Map<Long, String> orderBuyerNameMap = new HashMap<>(MapUtils.initCapacity(orderExes.size()));
            //过滤买家昵称
            boolean finalFilterBuyer = filterBuyer;
            orderExes = orderExes.stream().filter(orderEx -> {
                Long uid = orderEx.getUserId();
                //TODO 应当将userName冗余到order表中
                Result<String> unameRes = userClient.queryUserNameById(uid);
                if (unameRes != null && !StringUtils.isEmpty(unameRes.getData())) {
                    orderBuyerNameMap.put(orderEx.getId(), unameRes.getData());

                    if (finalFilterBuyer) {
                        if (unameRes.getData().equals(input.getBuyerName())) {
                            //买家符合搜索条件
                            return true;
                        }
                        return false;
                    } else {
                        return true;
                    }
                } else {
                    orderBuyerNameMap.put(orderEx.getId(), "买家查询异常");
                }
                return true;
            }).collect(Collectors.toList());
            for (OrderEx orderEx : orderExes) {
                List<OrderShop> orderShopList = orderEx.getOrderShopList();
                if (orderShopList != null && orderShopList.size() > 0) {
                    boolean filterShop = false;
                    if (!StringUtils.isEmpty(input.getShopName())) {
                        filterShop = true;
                    }
                    for (OrderShop orderShop : orderShopList) {
                        vo = new OrderShopEx();
                        String buyerName = orderBuyerNameMap.get(orderShop.getOrderId());
                        vo.setBuyerName(StringUtils.isEmpty(buyerName) ? "买家查询异常" : buyerName);
                        Result<Shop> shopResult = shopClient.queryByIdIn(orderShop.getShopId());
                        if (shopResult != null && shopResult.getData() != null) {
                            String shopName = shopResult.getData().getName();
                            if (filterShop && shopName.indexOf(input.getShopName()) < 0) {
                                //店铺名不符合过滤规则
                                orderShopIdSet.remove(orderShop.getId());
                                continue;
                            }

                            vo.setShopName(shopName);
                        } else {
                            vo.setShopName("----");
                        }
                        BeanUtils.copyProperties(orderShop, vo);
                        vo.setCreateTime(orderEx.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss")));
                        vo.setType(orderEx.getType());
                        res.add(vo);
                    }
                }
            }
        }
        return new PageResult<>(res, (long) orderShopIdSet.size());
    }


    public Order queryOrder(Long orderId) {
        return orderMapper.selectById(orderId);
    }

    public Order queryOrderStatus(Long orderId) {
        return orderMapper.selectStatus(orderId);
    }

    /**
     * 保存积分日志
     *
     * @param orderId        订单
     * @param userId         用户id
     * @param freezeIntegral 冻结积分
     * @param totalIntegral  使用/返还积分
     * @param useIntegral    是否使用积分
     * @param cancel         取消/提交 订单
     */
    private void saveIntegralAction(Long orderId, Long userId, Integer freezeIntegral, Integer totalIntegral, Boolean useIntegral, Boolean cancel) {
        List<IntegralAction> actionList = Lists.newArrayListWithCapacity(2);
        if (useIntegral) {
            IntegralAction.IntegralActionBuilder builder = IntegralAction.builder().createTime(DateUtils.now()).num(totalIntegral)
                    .relatedId(orderId)
                    .userId(userId);
            if (cancel) {
                builder.freeze(IntegralActionType.CANCEL_ORDER.getFreeze())
                        .incr(IntegralActionType.CANCEL_ORDER.getIncr())
                        .type(IntegralActionType.CANCEL_ORDER.getType());

            } else {
                builder.freeze(IntegralActionType.SUBMIT_ORDER.getFreeze())
                        .incr(IntegralActionType.SUBMIT_ORDER.getIncr())
                        .type(IntegralActionType.SUBMIT_ORDER.getType());
            }
            actionList.add(builder.build());
        }
        if (freezeIntegral > 0) {
            IntegralAction.IntegralActionBuilder builder = IntegralAction.builder().createTime(DateUtils.now()).num(freezeIntegral)
                    .relatedId(orderId)
                    .userId(userId);
            if (cancel) {
                builder.freeze(IntegralActionType.GOODS_OUT_FREEZE.getFreeze())
                        .incr(IntegralActionType.GOODS_OUT_FREEZE.getIncr())
                        .type(IntegralActionType.GOODS_OUT_FREEZE.getType());
            } else {
                builder.freeze(IntegralActionType.GOODS_IN_FREEZE.getFreeze())
                        .incr(IntegralActionType.GOODS_IN_FREEZE.getIncr())
                        .type(IntegralActionType.GOODS_IN_FREEZE.getType());
            }
            actionList.add(builder.build());
        }
        if (actionList.size() > 0) {
            Result<Void> result = integralActionClient.saveBatch(actionList);
        }
    }


    /**
     * 修改优惠券状态
     *
     * @param userId    用户id
     * @param order     订单
     * @param couponIds 优惠券ids
     * @param used      是否使用
     */
    private void updateCouponUsed(Long userId, Order order, List<Long> couponIds, boolean used) {
        if (ObjectUtil.isEmpty(couponIds)&&order.getSysCouponId()==null) {
            return;
        }
        if (ObjectUtil.isNotEmpty(couponIds)){
            couponIds = couponIds.stream().filter(Objects::nonNull).collect(Collectors.toList());
        }
        if (ObjectUtil.isEmpty(couponIds)&&order.getSysCouponId()==null) {
            return;
        }
        int modifyCount = 0;
        boolean updated = false;
        if (order.getSysCouponId() == null) {
            if (couponIds.size() > 0) {
                //优惠券使用次数+1
                updated = true;
                modifyCount = mgCouponService.useCoupon(couponIds, used);
                couponClient.useCoupon(UseCouponInput.builder().couponIds(couponIds).orderId(used ? order.getId() : null).usedTime(used ? DateUtils.now() : null).used(used).userId(userId).build());
            }
        } else if (order.getSysCouponId() > 0) {
            //优惠券使用次数+1
            updated = true;

            modifyCount = mgCouponService.useCoupon(Lists.newArrayList(order.getSysCouponId()), used);
            couponClient.useCoupon(UseCouponInput.builder().couponIds(Lists.newArrayList(order.getSysCouponId())).orderId(used ? order.getId() : null).usedTime(used ? DateUtils.now() : null).used(used).userId(userId).build());
        }
        if (modifyCount <= 0 && updated) {
            log.error("修改优惠券状态失败{},used:{},order:{},userId:{}", couponIds, used, order, userId);
        }
    }

    /**
     * 删除店铺订单
     *
     * @return false:非当前订单用户删除/订单不存在 true:删除成功
     */
    @Transactional(rollbackFor = MaiMaoDaoException.class)
    public Result delete(Long orderShopId, Long userId) {
        OrderShop orderShop = orderShopMapper.selectById(orderShopId);
        if (orderShop != null) {
            Integer status = orderShop.getStatus();
            // 除了未支付、交易成功和交易取消可以删除，其他状态不允许删除
            if (!status.equals(OrderShopStatus.NOT_PAY.getStatus()) && !status.equals(OrderShopStatus.SUCCESS.getStatus()) && !status.equals(OrderShopStatus.CANCEL.getStatus())) {
                return Result.fail("订单进行中，不可删除");
            }
            Long orderId = orderShop.getOrderId();
            List<OrderShop> orderShops = orderShopMapper.selectByOrderId(orderId);
            if (orderShops != null && orderShops.size() > 0) {
                boolean flag = false;
                for (OrderShop shop : orderShops) {
                    if (!shop.getDeleted() && !shop.getId().equals(orderShopId)) {
                        //当前订单的店铺订单没有全部删除
                        flag = true;
                        break;
                    }
                }
                Order order = orderMapper.selectById(orderId);
                if (!order.getUserId().equals(userId)) {
                    //非当前用户操作
                    return Result.fail("非法用户");
                }
                //删除店铺订单
                orderShopMapper.updateDeleted(orderShopId, 1);
                if (!flag) {
                    //如果店铺订单全部被删除 则删除order表标识
                    orderMapper.deleteLogic(orderId);
                }
                return Result.ok();
            }
            return Result.fail("订单不存在");
        } else {
            return Result.fail("订单不存在");
        }
    }

    /**
     * 发货
     *
     * @param id          orderGoodsId
     * @param orderShopId orderShopId
     */
    @Transactional(rollbackFor = MaiMaoDaoException.class)
    public Result delivery(Long id, Long orderShopId, Long orderId) {
        Order order = orderMapper.selectStatus(orderId);
        if (order == null) {
            return Result.notValid("无效订单");
        }
        if (!order.getStatus().equals(OrderStatus.PAID.getStatus())) {
            return Result.notValid("订单未付款或已取消，不可发货");
        }
        orderGoodsMapper.changeShipStatus(id, 1);
        List<OrderGoods> orderGoods = orderGoodsMapper.selectShipStatusByOrderShopId(orderShopId);
        if (ObjectUtils.isNotEmpty(orderGoods)) {
            boolean notDelivery = false;
            for (OrderGoods orderGood : orderGoods) {
                if (orderGood.getShippedStatus() != null && orderGood.getShippedStatus().equals(ShipStatus.NOT_SHIP.getStatus())) {
                    notDelivery = true;
                    break;
                }
            }
            if (!notDelivery) {
                //orderShop订单全部发货
                orderShopMapper.updateStatusByShopId(orderShopId, OrderShopStatus.ALL_SHIP.getStatus());
            } else {
                //部分发货
                orderShopMapper.updateStatusByShopId(orderShopId, OrderShopStatus.PART_SHIP.getStatus());
            }
        }
        return Result.ok();
    }

    /**
     * 确认收货
     *
     * @param id          orderGoodsId
     * @param orderShopId orderShopId
     */
    @Transactional(rollbackFor = MaiMaoDaoException.class)
    public void receiveGoods(Long id, Long orderShopId) {
        orderGoodsMapper.receiveGoods(id, DateUtils.now());
        List<OrderGoods> orderGoods = orderGoodsMapper.selectShipStatusByOrderShopId(orderShopId);
        if (ObjectUtils.isNotEmpty(orderGoods)) {
            boolean receiveAll = true;
            for (OrderGoods orderGood : orderGoods) {
                if (!orderGood.getReceive()) {
                    receiveAll = false;
                    break;
                }
            }
            if (receiveAll) {
                //orderShop全部收货
                orderShopMapper.updateStatusByShopId(orderShopId, OrderShopStatus.SUCCESS.getStatus());
                List<OrderShop> orderShops = orderShopMapper.selectByOrderId(orderGoods.get(0).getOrderId());
                if (ObjectUtils.isNotEmpty(orderShops)) {
                    boolean allSuccess = true;
                    for (OrderShop orderShop : orderShops) {
                        if (!orderShop.getStatus().equals(OrderShopStatus.SUCCESS.getStatus())) {
                            allSuccess = false;
                            break;
                        }
                    }
                    if (allSuccess) {
                        //订单全部order_shop交易成功
                        orderMapper.updateStatus(orderGoods.get(0).getOrderId(), OrderStatus.SUCCESS.getStatus());
                    }
                }
            }
        }
    }

    /**
     * 更改订单评论状态
     */
    @Transactional(rollbackFor = MaiMaoDaoException.class)
    public void updateCommentStatus(CommentStatusUpdateInput input) {
        orderGoodsMapper.updateCommentStatus(input.getOrderId(), input.getSkuId(), input.getStatus());
    }

    public OrderGoods queryCommentStatus(CommentStatusUpdateInput input) {
        return orderGoodsMapper.selectCommentBySkuIdAndOrderId(input.getSkuId(), input.getOrderId());
    }


    /**
     * 获取导出订单数据
     */
    public List<ExportOrderEntity> export(OrderSearchInput input, Integer page, Integer size) {
        Result<PageResult<EsOrder>> resultResult = esClient.list(input, page, size);
        if (resultResult != null && resultResult.getData() != null && ObjectUtil.isNotEmpty(resultResult.getData().getRows())) {
            List<EsOrder> esOrderList = resultResult.getData().getRows();
            List<ExportOrderEntity> exportOrderEntityList = Lists.newArrayListWithCapacity(esOrderList.size() * 2);
            for (EsOrder esOrder : esOrderList) {
                for (EsOrderShop esOrderShop : esOrder.getOrderShopList()) {
                    for (EsOrderGoods esOrderGoods : esOrderShop.getOrderGoodsList()) {
                        ExportOrderEntity exportOrderEntity = new ExportOrderEntity();
                        BeanUtil.copyProperties(esOrder, exportOrderEntity);
                        BeanUtil.copyProperties(esOrderShop, exportOrderEntity, "id", "status", "deleted");
                        BeanUtil.copyProperties(esOrderGoods, exportOrderEntity, "id", "orderShopId", "integral");

                        exportOrderEntity.setOrderShopOrderStatus(esOrderShop.getStatus());
                        exportOrderEntity.setGiveIntegral(esOrderGoods.getIntegral());

                        exportOrderEntityList.add(exportOrderEntity);
                    }
                }
            }
            doFilter(input, exportOrderEntityList);
            return exportOrderEntityList;
        }
        return ListData.EMPTY_LIST;
    }

    /**
     * 由于es采用嵌套结构查询，shopId在orderShopList子结构中[包括其他需要嵌套查询的字段]，因此在查询时，如果一个order中存在多个orderShop对象，但是仅有部分匹配shopId,查询结果会将该order下的所有orderShop返回
     * 后期考虑通过父子关系文档结构是否可以处理，暂时没了解
     *
     * @desc 手动处理嵌套查询导致的问题 根据条件进一步过滤
     */
    private void doFilter(OrderSearchInput input, List<ExportOrderEntity> exportOrderEntityList) {
        if (ObjectUtil.isNotEmpty(exportOrderEntityList)) {
            Iterator<ExportOrderEntity> iterator = exportOrderEntityList.iterator();
            while (iterator.hasNext()) {
                ExportOrderEntity next = iterator.next();
                if (StrUtil.isNotEmpty(input.getTitle())) {
                    if (!StrUtil.containsIgnoreCase(next.getTitle(), input.getTitle())) {
                        iterator.remove();
                        continue;
                    }
                }

                if (input.getCommentType() != null) {
                    Boolean comment = input.getCommentType().equals(ONE);
                    if (!next.getComment().equals(comment)) {
                        iterator.remove();
                        continue;
                    }
                }

                if (input.getGoodsId() != null && input.getGoodsId() > 0) {
                    if (!next.getGoodsId().equals(input.getGoodsId().toString())) {
                        iterator.remove();
                        continue;
                    }
                }

                if (input.getShopId() != null && input.getShopId() > 0) {
                    if (!next.getShopId().equals(input.getShopId().toString())) {
                        iterator.remove();
                        continue;
                    }
                }

                if (StrUtil.isNotEmpty(input.getShopName())) {
                    if (!next.getShopName().equals(input.getShopName())) {
                        iterator.remove();
                        continue;
                    }
                }

                if (input.getStatus() != null) {
                    if (!next.getOrderShopOrderStatus().equals(input.getStatus())) {
                        iterator.remove();
                        continue;
                    }
                }

                if (input.getShippedStatus() != null) {
                    if (!next.getShippedStatus().equals(input.getShippedStatus())) {
                        iterator.remove();
                    }
                }


            }
        }
    }
}
